package com.lagou.edu.minicat;

import com.lagou.edu.minicat.classLoader.MyClassloader;
import com.lagou.edu.minicat.core.*;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.List;

/**
 * @author gaoguangyang
 */
public class BootstrapV4 {

    public static void main(String[] args) throws Exception {
        BootstrapV4 bootstrapV4 = new BootstrapV4();
        bootstrapV4.init();
    }

    private Server server;

    public void init() throws Exception {
        // 解析server.xml文件
        loadServerXml();
        server.init();
        this.server.start();
    }

    /**
     * 整体初始化server.xml中的内容
     *
     * @throws Exception
     */
    private void loadServerXml() throws Exception {
        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("server.xml");
        SAXReader saxReader = new SAXReader();
        Document server = saxReader.read(resourceAsStream);
        Element rootElement = server.getRootElement();

        // 根路径初始化server
        this.server = new Server();
        this.server.setService(createService(rootElement));
    }

    /**
     * 初始化service及下面的connector
     *
     * @param rootElement
     * @return
     * @throws Exception
     */
    private Service createService(Element rootElement) throws Exception {
        // 初始化service
        Element serviceElement = (Element) rootElement.selectSingleNode("Service");
        Service service = new Service();
        service.setEngine(createEngine(serviceElement));

        // 初始化connector
        Element connectorElement = (Element) serviceElement.selectSingleNode("Connector");
        int port = Integer.parseInt(connectorElement.attributeValue("port"));
        Connector connector = new Connector();
        connector.setPort(port);
        connector.setService(service);
        this.server.setConnector(connector);
        return service;
    }

    /**
     * 初始化engine
     *
     * @param serviceElement
     * @return
     * @throws Exception
     */
    private Engine createEngine(Element serviceElement) throws Exception {
        Element engineElement = (Element) serviceElement.selectSingleNode("Engine");
        Engine engine = new Engine();
        engine.setHost(createHost(engineElement));
        return engine;
    }

    /**
     * 初始化host
     *
     * @param engineElement
     * @return
     * @throws Exception
     */
    private Host createHost(Element engineElement) throws Exception {
        Element hostElement = (Element) engineElement.selectSingleNode("Host");
        String name = hostElement.attributeValue("name");
        String appBase = hostElement.attributeValue("appBase");

        Host host = new Host();
        host.setName(name);
        host.setAppBase(appBase);

        createContext(host);
        return host;
    }

    private void createContext(Host host) throws Exception {
        File baseFile = new File(host.getAppBase());
        File[] files = baseFile.listFiles();
        if (files == null || files.length == 0) {
            return;
        }
        for (File file : files) {
            if (file.isDirectory()) {
                Context context = new Context();
                context.setContextName(file.getName());

                File classPath = new File(file, "/WEB-INF/classes");
                URL[] urls = {classPath.toURI().toURL()};
                context.setClassLoader(new MyClassloader(urls));

                // 加载各个项目中的web.xml
                context.addWrapper(createWrapper(file));
                host.addContext(context);
            }
        }
    }

    /**
     * 解析指定项目中的web.xml，并与host关联
     *
     * @param file
     * @return
     * @throws Exception
     */
    private Wrapper createWrapper(File file) throws Exception {
        File webXml = new File(file, "/WEB-INF/web.xml");
        if (webXml.exists()) {
            InputStream inputStream = new FileInputStream(webXml);
            SAXReader saxReader = new SAXReader();
            Document document = saxReader.read(inputStream);
            Element rootElement = document.getRootElement();

            List<Element> selectNodes = rootElement.selectNodes("//servlet");

            for (Element element : selectNodes) {
                Element servletNameEle = (Element) element.selectSingleNode("//servlet-name");
                String servletName = servletNameEle.getStringValue();
                Element servletClsEle = (Element) element.selectSingleNode("//servlet-class");
                String servletClass = servletClsEle.getStringValue();

                //根据servlet-name的值找到url-pattern
                Element servletMapping = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");
                String urlPattern = servletMapping.selectSingleNode("url-pattern").getStringValue();

                Wrapper wrapper = new Wrapper();
                wrapper.setServletName(servletName);
                wrapper.setClassName(servletClass);
                wrapper.setUrlPattern(urlPattern);
                return wrapper;
            }
        }
        return null;
    }
}
